package com.jctrip.hotel.management.service;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.threadpool.ExportOrderTaskThreadPool;
import com.jctrip.hotel.common.util.BeanUtil;
import com.jctrip.hotel.common.util.JsonUtil;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.domain.dao.*;
import com.jctrip.hotel.domain.dto.GetOrderDto;
import com.jctrip.hotel.domain.entity.*;
import com.jctrip.hotel.management.client.FeizhuClient;
import com.jctrip.hotel.management.model.param.*;
import com.jctrip.hotel.management.model.result.*;
import com.jctrip.hotel.management.thread.ExportOrderTaskThread;
import com.jctrip.hotel.management.util.JwtUtil;
import com.jctrip.hotel.common.util.OssUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderRecordService {

    private final String listJob = RedisKeyConstant.HT_MANAGEMENT_ORDER_RECENT + "-";
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private HtOrderRouteRecordDao htOrderRouteRecordDao;
    @Autowired
    private HtOrderSourceRecordDao htOrderSourceRecordDao;
    @Autowired
    private HtRouteChannelCodeDao htRouteChannelCodeDao;
    @Autowired
    private HtRouteCodeDao htRouteCodeDao;
    @Autowired
    private HtRouteInfoDao htRouteInfoDao;
    @Autowired
    private HtSourceCodeDao htSourceCodeDao;
    @Autowired
    private HtSourceInfoDao htSourceInfoDao;
    @Autowired
    private HtPricePolicyDao htPricePolicyDao;
    @Autowired
    private HtHotelStdInfoDao htHotelStdInfoDao;
    @Autowired
    private HtPriceCalendarDao htPriceCalendarDao;
    @Autowired
    private HtRouteCreditLogDao htRouteCreditLogDao;
    @Autowired
    private MgOrderLogDao mgorderLogDao;
    @Autowired
    private FeizhuClient feizhuClient;
    @Autowired
    private HtPriceCalendarCnbeDao htPriceCalendarCnbeDao;
    @Autowired
    private HtPriceCalendarAtourDao htPriceCalendarAtourDao;
    @Autowired
    private HtPriceCalendarRezenDao htPriceCalendarRezenDao;
    @Autowired
    private HtPriceCalendarGreentreeDao htPriceCalendarGreentreeDao;
    @Autowired
    private HtPriceCalendarElongDao htPriceCalendarElongDao;
    @Autowired
    private HtPriceCalendarElongProductDao htPriceCalendarElongProductDao;
    @Autowired
    private MgUserInfoDao mgUserInfoDao;
    @Autowired
    private MgOssTaskDao mgOssTaskDao;
    @Autowired
    private HtOrderErrorLogDao htOrderErrorLogDao;
    @Autowired
    private HtPriceCalendarHmeinDao htPriceCalendarHmeinDao;
    @Autowired
    private HtPriceCalendarHworldDao htPriceCalendarHworldDao;

    public GetOrderListResult listOrder(GetOrderListParam param) {
        /// 后续需要做订单缓存
//        String listTask = listJob + param.getUsername();
//        //点击查询的话 需要将redis缓存的订单数据删除
//        if (param.getFlag()) {
//            redisUtil.del(listTask);
//        }
//        Long total = redisUtil.lGetListSize(listTask);
//        if (total <= 0) {
//            List<GetOrderListResult.OrderInfo> records = getOrderRouteRecords(param);
//            if(null != records){
//                redisUtil.leftPushAll(listTask, records.stream().map(e -> (Object) e).collect(Collectors.toList()));
//            }
//        }
//        total = redisUtil.lGetListSize(listTask);
//        int page = Math.toIntExact(total / param.getPageSize()) + 1;
//        page = page >= param.getPageNum() ? param.getPageNum() : page;
//        int size = param.getPageSize();
//        int start = (page - 1) * size;
//        int end = Math.toIntExact(page * size >= total ? total : page * size);
//        GetOrderListResult result = new GetOrderListResult();
//        result.setTotal(total);
//        result.setOrderList(records);
//        result.setPageNum(page);
//        result.setPageSize(size);
        return getOrderRouteRecords(param);
    }

    public void exportExcel(ExportOrderXlsxParam param, HttpServletRequest request) {
        // 异步导出订单
        MgOssTask mgOssTask = new MgOssTask();
        Date date = new Date();
        mgOssTask.setFileName(String.format("订单列表-%s-%d",
                new SimpleDateFormat("yyyy-MM").format(date), date.getTime()));
        mgOssTask.setUserId(String.valueOf(getUser(request).getId()));
        mgOssTaskDao.insert(mgOssTask);
        ExportOrderTaskThread exportOrderTaskThread =
                new ExportOrderTaskThread(param, mgOssTask.getId());
        ExportOrderTaskThreadPool.execute(exportOrderTaskThread);
    }

    public void export(ExportOrderXlsxParam param, Long id) {
        List<ExportOrderXlsxResult> records = exportXlsx(param);
        String result = OssUtil.updaload(ListToExcelOutPutStream(records, ExportOrderXlsxResult.class));
        MgOssTask info = mgOssTaskDao.selectById(id);
        if ("error".equals(result)) {
            info.setFileStatus(-1);
        } else {
            info.setFileStatus(1);
            info.setFileUrl(result);
        }
        info.setUpdateTime(new Date());
        mgOssTaskDao.updateById(info);
    }

    public List<ExportOrderXlsxResult> exportXlsx(ExportOrderXlsxParam param) {
        //获取符合预期的orderIds
        List<String> orderList = getExportOrderList(param);
        if (CollectionUtils.isEmpty(orderList)) {
            log.info("param {} 导出失败", JsonUtil.toString(param));
            return null;
        }
        LambdaQueryWrapper<HtOrderRouteRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(HtOrderRouteRecord::getOrderId, orderList);
        List<HtOrderRouteRecord> records = htOrderRouteRecordDao.selectList(lambdaQueryWrapper.select(HtOrderRouteRecord::getRouteId,
                HtOrderRouteRecord::getOrderId, HtOrderRouteRecord::getRouteOrderId, HtOrderRouteRecord::getRouteOrderStatus,
                HtOrderRouteRecord::getRouteHotelId, HtOrderRouteRecord::getRouteHotelName, HtOrderRouteRecord::getArriveDate,
                HtOrderRouteRecord::getDepartDate, HtOrderRouteRecord::getRoomCount, HtOrderRouteRecord::getContactName,
                HtOrderRouteRecord::getContactTel, HtOrderRouteRecord::getCompanyName, HtOrderRouteRecord::getCompanyPayment,
                HtOrderRouteRecord::getManualNotes, HtOrderRouteRecord::getReceivablePrice, HtOrderRouteRecord::getPaymentPrice,
                HtOrderRouteRecord::getCommissionPrice, HtOrderRouteRecord::getProfitPrice, HtOrderRouteRecord::getOrderCreateTime,
                HtOrderRouteRecord::getRouteRatePlanName, HtOrderRouteRecord::getRouteExtendOrderId)
                .orderByDesc(HtOrderRouteRecord::getCreateTime));
        List<ExportOrderXlsxResult> xlsxResults = new ArrayList<>();
        BigDecimal zero = BigDecimal.ZERO;
        records.forEach(item -> {
            ExportOrderXlsxResult xlsxResult = new ExportOrderXlsxResult();
            BeanUtil.copyProperties(item, xlsxResult);
            xlsxResult.setRouteName(htRouteInfoDao.selectOne(new LambdaQueryWrapper<HtRouteInfo>()
                    .eq(HtRouteInfo::getRouteId, item.getRouteId()).select(HtRouteInfo::getRouteName)).getRouteName());
            //渠道订单状态(0-未支付；10-已支付；20-已确认；21-拒绝新订；30-已完成；40-申请取消；41-同意取消；42-拒绝取消；50-已退款)
            xlsxResult.setRouteOrderStatus(getRouteOrderStatus(item.getRouteOrderStatus()));
            xlsxResult.setRoomNight(
                    DateUtil.between(item.getArriveDate(), item.getDepartDate(), DateUnit.DAY) * xlsxResult.getRoomCount());
            if (null == item.getCompanyPayment()) {
                xlsxResult.setCompanyPayment(null);
            } else if (item.getCompanyPayment() == 1) {
                xlsxResult.setCompanyPayment("是");
            } else {
                xlsxResult.setCompanyPayment("否");
            }
            xlsxResult.setRouteOrderCreateTime(item.getOrderCreateTime());
            AtomicReference<Boolean> flag = new AtomicReference<>(true);
            Optional.ofNullable(htOrderSourceRecordDao.selectList(
                    new LambdaQueryWrapper<HtOrderSourceRecord>()
                            .eq(HtOrderSourceRecord::getOrderId, item.getOrderId())
                            .select(HtOrderSourceRecord::getSourceCode,
                                    HtOrderSourceRecord::getSourceId, HtOrderSourceRecord::getSourceOrderId,
                                    HtOrderSourceRecord::getSourceOrderStatus, HtOrderSourceRecord::getPurchasePrice,
                                    HtOrderSourceRecord::getOrderCreateTime, HtOrderSourceRecord::getHotelId,
                                    HtOrderSourceRecord::getBookId)
                            .orderByDesc(HtOrderSourceRecord::getOrderCreateTime)))
                    .orElse(new ArrayList<>())
                    .forEach(htOrderSourceRecord -> {
                        ExportOrderXlsxResult newxlsxResult = new ExportOrderXlsxResult();
                        BeanUtil.copyProperties(xlsxResult, newxlsxResult);
                        newxlsxResult.setSourceCode(htSourceCodeDao.selectOne(new LambdaQueryWrapper<HtSourceCode>()
                                .eq(HtSourceCode::getCode, htOrderSourceRecord.getSourceCode()).select(HtSourceCode::getName)).getName());
                        newxlsxResult.setSourceName(htSourceInfoDao.selectOne(new LambdaQueryWrapper<HtSourceInfo>()
                                .eq(HtSourceInfo::getSourceId, htOrderSourceRecord.getSourceId())
                                .select(HtSourceInfo::getSourceName)).getSourceName());
                        newxlsxResult.setSourceOrderId(htOrderSourceRecord.getSourceOrderId());
                        newxlsxResult.setPurchasePrice(htOrderSourceRecord.getPurchasePrice());
                        newxlsxResult.setSourceHotelId(htOrderSourceRecord.getHotelId());
                        newxlsxResult.setSourceOrderCreateTime(htOrderSourceRecord.getOrderCreateTime());
                        newxlsxResult.setBookId(htOrderSourceRecord.getBookId());
                        //供应订单状态(0-待确认；1-预定成功；2-已取消；3-预定未到；4-已入住；5-已离店；6-预定失败)
                        newxlsxResult.setSourceOrderStatus(getSourceOrderStatus(htOrderSourceRecord.getSourceOrderStatus()));
                        if (!flag.get()) {
                            newxlsxResult.setReceivablePrice(zero);
                            newxlsxResult.setPaymentPrice(zero);
                        }
                        newxlsxResult.setProfitPrice(newxlsxResult.getPurchasePrice() != null ?
                                newxlsxResult.getReceivablePrice().subtract(newxlsxResult.getPurchasePrice()) : null);
                        xlsxResults.add(newxlsxResult);
                        flag.set(false);
                    });
        });
        return xlsxResults;
    }

    public UpdateNotesResult editNotes(UpdateNotesParam param, HttpServletRequest request) {
        boolean result = false;
        if (StringUtils.isBlank(param.getManualNotes()) || StringUtils.isBlank(param.getOrderId())) {
            return UpdateNotesResult.builder().result(result).build();
        }
        HtOrderRouteRecord record = htOrderRouteRecordDao.selectOne(new LambdaQueryWrapper<HtOrderRouteRecord>()
                .eq(HtOrderRouteRecord::getOrderId, param.getOrderId()));
        if (record == null) {
            return UpdateNotesResult.builder().result(result).build();
        }
        record.setManualNotes(param.getManualNotes());
        result = htOrderRouteRecordDao.updateById(record) == 1;
        insertOrderLog(record.getRouteId(), record.getOrderId(),
                org.apache.commons.lang.StringUtils.isNotBlank(request.getHeader("token")) ?
                        JwtUtil.parseJwt(request.getHeader("token")).getSubject() : "system", param.getManualNotes());
        return UpdateNotesResult.builder().result(result).build();
    }

    public GetSearchPriceResult searchPriceResult(GetPriceParam param) {
        if (StringUtils.isBlank(param.getHotelId())
                || StringUtils.isBlank(param.getRoomTypeCode())
                || StringUtils.isBlank(param.getRouteId())) {
            throw new RuntimeException("参数为空");
        }
        if (StringUtils.isBlank(param.getArriveDate()) || StringUtils.isBlank(param.getDepartDate())) {
            throw new RuntimeException("入离时间参数为空");
        }
        // 价格政策配置
        List<HtPricePolicy> htPricePolicies = getPricePolicies(param.getRouteId());
        List<String> sourceCodes = htPricePolicies.stream()
                .map(HtPricePolicy::getSourceCode)
                .collect(Collectors.toList());
        // 酒店标准信息
        HtHotelStdInfo htHotelStdInfo = getHotelStdInfo(param.getHotelId(), sourceCodes);
        if (htHotelStdInfo == null) {
            throw new RuntimeException("无效的hotelId");
        }
        htPricePolicies = htPricePolicies.stream()
                .filter(e -> e.getSourceCode().equals(htHotelStdInfo.getSourceCode()))
                .collect(Collectors.toList());
        Date beginDate = com.jctrip.hotel.common.util.DateUtil.parseDate(param.getArriveDate(), "yyyy-MM-dd");
        Date endDate = DateUtils.addDays(com.jctrip.hotel.common.util.DateUtil.parseDate(param.getDepartDate(), "yyyy-MM-dd"), -1);
        if (SourceEnum.CNBE.getCode().equals(htHotelStdInfo.getSourceCode())
                || SourceEnum.CNBEINT.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getCnbePriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.ATOUR.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getAtourPriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.REZEN.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getRezenPriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.GREENTREE.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getGreentreePriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.ELONGDOM.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getElongPriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.HMEIN.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getHmeinPriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        if (SourceEnum.HWORLD.getCode().equals(htHotelStdInfo.getSourceCode())) {
            return getHworldPriceCalendars(param.getHotelId(), param.getRoomTypeCode(),
                    beginDate, endDate, htPricePolicies);
        }
        // 价格日历
        List<HtPriceCalendar> htPriceCalendars =
                getPriceCalenders(param.getHotelId(), param.getRoomTypeCode(), beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendar htPriceCalendar : htPriceCalendars) {
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    public List<GetOrderLogResult> getLogs(String routeId, String orderId) {
        if (StringUtils.isBlank(routeId)) {
            throw new RuntimeException("渠道账户不能为空");
        }
        if (StringUtils.isBlank(orderId)) {
            throw new RuntimeException("订单号不能为空");
        }
        HtOrderRouteRecord htOrderRouteRecord = Optional.ofNullable(htOrderRouteRecordDao.selectOne(new LambdaQueryWrapper<HtOrderRouteRecord>()
                .eq(HtOrderRouteRecord::getRouteId, routeId).eq(HtOrderRouteRecord::getRouteOrderId, orderId))).orElse(new HtOrderRouteRecord());
        List<GetOrderLogResult> results = new ArrayList<>();
        List<MgOrderLog> mgOrderLogs = Optional.ofNullable(mgorderLogDao.selectList(new LambdaQueryWrapper<MgOrderLog>()
                .eq(MgOrderLog::getOrderId, htOrderRouteRecord.getOrderId()).eq(MgOrderLog::getRouteId, routeId))).orElse(new ArrayList<>());
        mgOrderLogs.forEach(mgOrderLog -> {
            GetOrderLogResult getOrderLogResult = GetOrderLogResult.builder()
                    .createTime(mgOrderLog.getCreateTime())
                    .info(mgOrderLog.getInfo())
                    .operator(mgOrderLog.getOperator())
                    .build();
            results.add(getOrderLogResult);
        });

        List<HtRouteCreditLog> htRouteCreditLogs = Optional.ofNullable(htRouteCreditLogDao.selectList(new LambdaQueryWrapper<HtRouteCreditLog>()
                .eq(HtRouteCreditLog::getOrderId, htOrderRouteRecord.getOrderId()).eq(HtRouteCreditLog::getRouteId, routeId))).orElse(new ArrayList<>());
        htRouteCreditLogs.forEach(htRouteCreditLog -> {
            GetOrderLogResult getOrderLogResult = GetOrderLogResult.builder()
                    .createTime(htRouteCreditLog.getCreateTime())
                    .operator(htRouteCreditLog.getOperator())
                    .build();
            if (htRouteCreditLog.getCreditType() == 1) {
                getOrderLogResult.setInfo(String.format("商家%s订单下单", htRouteCreditLog.getOrderId()));
            }
            if (htRouteCreditLog.getCreditType() == 2) {
                getOrderLogResult.setInfo(String.format("商家%s订单退款", htRouteCreditLog.getOrderId()));
            }
            results.add(getOrderLogResult);
        });
        results.sort(new Comparator<GetOrderLogResult>() {
            @Override
            public int compare(GetOrderLogResult o1, GetOrderLogResult o2) {
                if (o1.getCreateTime().getTime() != o2.getCreateTime().getTime()) {
                    if (o1.getCreateTime().getTime() > o2.getCreateTime().getTime()) {
                        return -1;
                    }
                    return 1;
                }
                return 0;
            }
        });
        return results;
    }

    public GetExportListResult exportList(HttpServletRequest request, Long pageNum, Long pageSize) {
        Page<MgOssTask> page = new Page<>();
        page.setCurrent(pageNum != null && pageNum > 0L ? pageNum : 1L);
        page.setSize(pageSize != null && pageSize > 0L ? pageSize : 10L);
        List<GetExportListResult.TaskInfo> records = new ArrayList<>();
        Page<MgOssTask> mgOssTaskPage = Optional.ofNullable(mgOssTaskDao.selectPage(page, new LambdaQueryWrapper<MgOssTask>()
                .eq(MgOssTask::getUserId, getUser(request).getId())
                .orderByDesc(MgOssTask::getCreateTime))).orElse(new Page<>());
        mgOssTaskPage.getRecords().forEach(mgOssLog -> {
            GetExportListResult.TaskInfo taskInfo = GetExportListResult.TaskInfo.builder()
                    .id(String.valueOf(mgOssLog.getId())).build();
            BeanUtil.copyProperties(mgOssLog, taskInfo);
            records.add(taskInfo);
        });
        return GetExportListResult.builder().current(mgOssTaskPage.getCurrent())
                .pages(mgOssTaskPage.getPages()).size(mgOssTaskPage.getSize())
                .total(mgOssTaskPage.getTotal()).records(records).build();
    }

    public URL download(String id, HttpServletResponse response) {
        MgOssTask mgOssTask = mgOssTaskDao.selectById(id);
        return OssUtil.download(mgOssTask.getFileUrl());
    }

    public String deleteExport(String id) {
        String info = Optional.ofNullable(mgOssTaskDao.selectById(id))
                .orElse(new MgOssTask()).getFileUrl();
        boolean flag = mgOssTaskDao.deleteById(id) == 1;
        if (flag && StringUtils.isNotBlank(info)) {
            OssUtil.delete(info);
        }
        return flag ? "操作成功" : "操作失败";
    }

    private byte[] ListToExcelOutPutStream(List<?> lst, Class clazz) {
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        ExcelWriter excelWriter = EasyExcel.write(arrayOutputStream, clazz).autoCloseStream(true).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        excelWriter.write(lst, writeSheet);
        excelWriter.finish();
        return arrayOutputStream.toByteArray();
    }

    private GetOrderListResult getOrderRouteRecords(GetOrderListParam param) {
        if (Objects.nonNull(param.getText())) {
            param.setText(param.getText().trim());
        }
        if (Objects.nonNull(param.getRouteOrderId())) {
            param.setRouteOrderId(param.getRouteOrderId().trim());
        }
        if (Objects.nonNull(param.getSourceOrderId())) {
            param.setSourceOrderId(param.getSourceOrderId().trim());
        }
        if (Objects.nonNull(param.getDepartDate())) {
            param.setDepartDate(DateUtil.endOfDay(param.getDepartDate()));
        }
        param.setPageNo((param.getPageNo() - 1) * param.getPageSize());
        GetOrderDto dto = new GetOrderDto();
        BeanUtil.copyProperties(param, dto);

        //获取符合预期的orderIds
        List<String> orderList = htOrderRouteRecordDao.selectOrderIds(dto);
        if (CollectionUtils.isEmpty(orderList)) {
            return null;
        }

        // 找到当前orderId下的所有routeOrder
        List<HtOrderRouteRecord> routeRecords = selectRouteOrders(orderList);
        if (CollectionUtils.isEmpty(routeRecords)) {
            return null;
        }

        // 找到当前orderId下的所有sourceOrder
        List<HtOrderSourceRecord> sourceRecords = selectSourceOrders(orderList);
        if (CollectionUtils.isEmpty(sourceRecords)) {
            return null;
        }

        Map<String, List<HtOrderSourceRecord>> sourceOrderMap =
                sourceRecords.stream().collect(Collectors.groupingBy(HtOrderSourceRecord::getOrderId));

        List<HtRouteInfo> routeInfos = selectRouteInfos(routeRecords.stream().map(HtOrderRouteRecord::getRouteId).distinct().collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(routeInfos)) {
            return null;
        }

        List<HtRouteChannelCode> routeChannelCodes = selectRouteChannelCodes(routeRecords.stream().map(HtOrderRouteRecord::getRouteChannelCode).distinct().collect(Collectors.toList()));

        List<HtRouteCode> routeCodes = selectRouteCodes(routeInfos.stream().map(HtRouteInfo::getRouteCode).distinct().collect(Collectors.toList()));

        List<HtSourceInfo> sourceInfos = selectSourceInfos(sourceRecords.stream().map(HtOrderSourceRecord::getSourceId).distinct().collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(sourceInfos)) {
            return null;
        }

        List<GetOrderListResult.OrderInfo> orderInfos = routeRecords.stream()
                .map(item -> {
                    GetOrderListResult.OrderInfo orderInfo = new GetOrderListResult.OrderInfo();
                    BeanUtil.copyProperties(item, orderInfo);
                    GetHotelNameParam hotelNameParam = new GetHotelNameParam();
                    hotelNameParam.setHid(item.getRouteHotelId());

                    GetRoomTypeCodeParam roomTypeCodeParam = new GetRoomTypeCodeParam();
                    roomTypeCodeParam.setRid(item.getRouteRoomTypeCode());
                    roomTypeCodeParam.setHid(item.getRouteHotelId());

                    HtRouteChannelCode htRouteChannelCode = routeChannelCodes.stream()
                            .filter(e -> e.getCode().equals(item.getRouteChannelCode())).findFirst().orElse(new HtRouteChannelCode());

                    orderInfo.setRouteChannelName(routeInfos.stream()
                            .filter(e -> e.getRouteId().equals(item.getRouteId())).findFirst().orElse(new HtRouteInfo()).getRouteName());


                    orderInfo.setRouteChannelName(orderInfo.getRouteChannelName() + "-"
                            + routeCodes.stream().filter(e -> e.getCode().equals(item.getRouteCode()))
                            .findFirst().orElse(new HtRouteCode()).getName());

                    if (StringUtils.isNotBlank(htRouteChannelCode.getName())) {
                        orderInfo.setRouteChannelName(orderInfo.getRouteChannelName() + "-" + htRouteChannelCode.getName());
                    }
                    // 前期数据不全 进行的修正 现在
//                    if ("fliggyNewbiz".equals(item.getRouteCode()) || "fliggyHotel".equals(item.getRouteCode())) {
//                        if (StringUtils.isBlank(orderInfo.getHotelId())) {
//                            Result<GetHotelIdResult> hotelId = feizhuClient.getHotelId(hotelNameParam);
//                            if (hotelId != null && hotelId.getCode() == 200) {
//                                orderInfo.setHotelId(hotelId.getResult().getHotelId());
//                            }
//                        }
//
//                        if (StringUtils.isBlank(orderInfo.getRoomTypeCode())) {
//                            Result<GetRoomTypeCodeResult> roomTypeCodeResultResult = feizhuClient.getRoomTypeCode(roomTypeCodeParam);
//                            if (roomTypeCodeResultResult != null && roomTypeCodeResultResult.getCode() == 200) {
//                                orderInfo.setRoomTypeCode(roomTypeCodeResultResult.getResult().getRoomTypeCode());
//                            }
//                        }
//
//                        if (StringUtils.isBlank(orderInfo.getRouteHotelName())) {
//                            Result<GetHotelNameResult> hotelName = feizhuClient.getHotelName(hotelNameParam);
//                            if (hotelName != null && hotelName.getCode() == 200) {
//                                orderInfo.setRouteHotelName(hotelName.getResult().getName());
//                            }
//                        }
//                    }
//                    if (StringUtils.isBlank(orderInfo.getRouteRoomTypeName())) {
//                        GetRoomTypeNameParam roomTypeNameParam = new GetRoomTypeNameParam();
//                        roomTypeNameParam.setRid(item.getRouteRoomTypeCode());
//                        Result<GetRoomTypeNameResult> roomTypeName = feizhuClient.getRoomTypeName(roomTypeNameParam);
//                        if (roomTypeName != null && roomTypeName.getCode() == 200) {
//                            orderInfo.setRouteRoomTypeName(roomTypeName.getResult().getName());
//                        }
//                    }
                    orderInfo.setRoomNight(DateUtil.between(item.getArriveDate(), item.getDepartDate(), DateUnit.DAY));
                    orderInfo.setSourceOrderList(getSourceOrderList(sourceOrderMap.get(item.getOrderId()), sourceInfos));
                    return orderInfo;
                }).collect(Collectors.toList());
        GetOrderListResult result = new GetOrderListResult();
        result.setOrderList(orderInfos);
        result.setTotal(htOrderRouteRecordDao.selectOrdersNum(dto));
        result.setPageSize(param.getPageSize());
        result.setPageNum(param.getPageNo());
        return result;
    }

    private List<HtOrderRouteRecord> selectRouteOrders(List<String> orderList) {
        LambdaQueryWrapper<HtOrderRouteRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtOrderRouteRecord::getOrderId, orderList);
        wrapper.select(HtOrderRouteRecord::getOrderId, HtOrderRouteRecord::getRouteOrderId, HtOrderRouteRecord::getRouteId,
                HtOrderRouteRecord::getCompanyName, HtOrderRouteRecord::getCompanyPayment, HtOrderRouteRecord::getRouteChannelCode,
                HtOrderRouteRecord::getRouteHotelId, HtOrderRouteRecord::getRouteHotelName, HtOrderRouteRecord::getRouteCode,
                HtOrderRouteRecord::getContactName, HtOrderRouteRecord::getContactTel, HtOrderRouteRecord::getRouteRoomTypeCode,
                HtOrderRouteRecord::getRouteRoomTypeName, HtOrderRouteRecord::getBreakfastCount, HtOrderRouteRecord::getRouteId,
                HtOrderRouteRecord::getGuestName, HtOrderRouteRecord::getArriveDate, HtOrderRouteRecord::getDepartDate,
                HtOrderRouteRecord::getRoomCount, HtOrderRouteRecord::getPaymentType, HtOrderRouteRecord::getProfitPrice,
                HtOrderRouteRecord::getPaymentPrice, HtOrderRouteRecord::getReceivablePrice, HtOrderRouteRecord::getCreateTime,
                HtOrderRouteRecord::getStockType, HtOrderRouteRecord::getPriceType, HtOrderRouteRecord::getOrderCreateTime,
                HtOrderRouteRecord::getManualNotes, HtOrderRouteRecord::getRouteOrderStatus, HtOrderRouteRecord::getRouteRatePlanName);
        wrapper.orderByDesc(HtOrderRouteRecord::getCreateTime);
        return htOrderRouteRecordDao.selectList(wrapper);
    }

    private List<HtOrderSourceRecord> selectSourceOrders(List<String> orderList) {
        LambdaQueryWrapper<HtOrderSourceRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtOrderSourceRecord::getOrderId, orderList);
        wrapper.select(HtOrderSourceRecord::getSourceCode, HtOrderSourceRecord::getBookId, HtOrderSourceRecord::getOrderId,
                HtOrderSourceRecord::getSourceOrderId, HtOrderSourceRecord::getPurchasePrice, HtOrderSourceRecord::getOperator,
                HtOrderSourceRecord::getSourceOrderStatus, HtOrderSourceRecord::getSourcePaymentStatus,
                HtOrderSourceRecord::getRoomTypeName, HtOrderSourceRecord::getSourceId, HtOrderSourceRecord::getContactName,
                HtOrderSourceRecord::getContactTel, HtOrderSourceRecord::getGuestName, HtOrderSourceRecord::getRealArriveTime,
                HtOrderSourceRecord::getRealDepartTime, HtOrderSourceRecord::getRefundPrice, HtOrderSourceRecord::getCurrencyCode,
                HtOrderSourceRecord::getRequestBody, HtOrderSourceRecord::getResponseBody, HtOrderSourceRecord::getHotelId,
                HtOrderSourceRecord::getHotelName, HtOrderSourceRecord::getRoomTypeCode);
        wrapper.orderByDesc(HtOrderSourceRecord::getOrderCreateTime);
        return htOrderSourceRecordDao.selectList(wrapper);
    }

    private List<HtRouteChannelCode> selectRouteChannelCodes(List<String> routeChannelCodes) {
        LambdaQueryWrapper<HtRouteChannelCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtRouteChannelCode::getCode, routeChannelCodes);
        wrapper.select(HtRouteChannelCode::getCode, HtRouteChannelCode::getName);
        return htRouteChannelCodeDao.selectList(wrapper);
    }

    private List<HtRouteInfo> selectRouteInfos(List<String> routeIds) {
        LambdaQueryWrapper<HtRouteInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtRouteInfo::getRouteId, routeIds);
        wrapper.select(HtRouteInfo::getRouteId, HtRouteInfo::getRouteName, HtRouteInfo::getRouteCode);
        return htRouteInfoDao.selectList(wrapper);
    }

    private List<HtRouteCode> selectRouteCodes(List<String> routeCodes) {
        LambdaQueryWrapper<HtRouteCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtRouteCode::getCode, routeCodes);
        wrapper.select(HtRouteCode::getCode, HtRouteCode::getName);
        return htRouteCodeDao.selectList(wrapper);
    }

    private List<HtSourceInfo> selectSourceInfos(List<String> sourceIds) {
        LambdaQueryWrapper<HtSourceInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtSourceInfo::getSourceId, sourceIds);
        wrapper.select(HtSourceInfo::getSourceId, HtSourceInfo::getSourceName);
        return htSourceInfoDao.selectList(wrapper);
    }

    private List<HtOrderErrorLog> selectErrorLogs(List<String> bookIds) {
        LambdaQueryWrapper<HtOrderErrorLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(HtOrderErrorLog::getBookId, bookIds);
        wrapper.select(HtOrderErrorLog::getResponseBody);
        wrapper.orderByDesc(HtOrderErrorLog::getCreateTime);
        return htOrderErrorLogDao.selectList(wrapper);
    }

    private GetSearchPriceResult getCnbePriceCalendars(String hotelId, String roomTypeCode, Date beginDate, Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarCnbe> htPriceCalendars =
                getCnbePrices(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendarCnbe htPriceCalendar : htPriceCalendars) {
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private GetSearchPriceResult getHworldPriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                        Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarHworld> htPriceCalendars =
                getPriceCalendersHworld(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendarHworld htPriceCalendar : htPriceCalendars) {
                // todo 添加对应的价格计划
                if (!htPriceCalendar.getSourceId().equals(htPricePolicy.getSourceId())) {
                    continue;
                }
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private GetSearchPriceResult getHmeinPriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                            Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarHmein> htPriceCalendars =
                getPriceCalendersHmein(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendarHmein htPriceCalendar : htPriceCalendars) {
                // todo 添加对应的价格计划
                if (!htPriceCalendar.getSourceId().equals(htPricePolicy.getSourceId())) {
                    continue;
                }
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private GetSearchPriceResult getGreentreePriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                            Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarGreentree> htPriceCalendars =
                getPriceCalendersGreentree(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendarGreentree htPriceCalendar : htPriceCalendars) {
                // todo 添加对应的价格计划
                if (!htPriceCalendar.getSourceId().equals(htPricePolicy.getSourceId())) {
                    continue;
                }
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private GetSearchPriceResult getElongPriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                        Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarElong> htPriceCalendars =
                getPriceCalendersElong(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            // 找到当前product 对应的选择
            HtPriceCalendarElongProduct htPriceCalendarElongProduct =
                    htPriceCalendarElongProductDao.selectOne(new LambdaQueryWrapper<HtPriceCalendarElongProduct>()
                            .eq(HtPriceCalendarElongProduct::getHotelId, hotelId)
                            .eq(HtPriceCalendarElongProduct::getRoomTypeCode, roomTypeCode)
                            .eq(HtPriceCalendarElongProduct::getSourceId, htPricePolicy.getSourceId())
                            .eq(HtPriceCalendarElongProduct::getProductCode, htPricePolicy.getProductCode())
                            .between(HtPriceCalendarElongProduct::getCalDate,
                                    com.jctrip.hotel.common.util.DateUtil.beginOfDay(new Date()),
                                    com.jctrip.hotel.common.util.DateUtil.endOfDay(new Date())));
            if (Objects.isNull(htPriceCalendarElongProduct)) {
                continue;
            }
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            for (HtPriceCalendarElong htPriceCalendar : htPriceCalendars) {
                if (!htPriceCalendar.getProductId().equals(htPriceCalendarElongProduct.getProductId())) {
                    continue;
                }
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private List<HtPriceCalendarElong> getPriceCalendersElong(String hotelId, String roomTypeCode,
                                                              Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarElong> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarElong::getHotelId, hotelId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarElong::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarElong::getCalDate, beginDate, endDate);
        return htPriceCalendarElongDao.selectList(queryWrapper);
    }

    private List<HtPriceCalendarHworld> getPriceCalendersHworld(String hotelId, String roomTypeCode,
                                                              Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarHworld> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarHworld::getHotelId, hotelId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarHworld::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarHworld::getCalDate, beginDate, endDate);
        return htPriceCalendarHworldDao.selectList(queryWrapper);
    }

    private List<HtPriceCalendarHmein> getPriceCalendersHmein(String hotelId, String roomTypeCode,
                                                                      Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarHmein> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarHmein::getHotelId, hotelId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarHmein::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarHmein::getCalDate, beginDate, endDate);
        return htPriceCalendarHmeinDao.selectList(queryWrapper);
    }

    private List<HtPriceCalendarGreentree> getPriceCalendersGreentree(String hotelId, String roomTypeCode,
                                                                      Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarGreentree> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarGreentree::getHotelId, hotelId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarGreentree::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarGreentree::getCalDate, beginDate, endDate);
        return htPriceCalendarGreentreeDao.selectList(queryWrapper);
    }

    private GetSearchPriceResult getAtourPriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                        Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarAtour> htPriceCalendars =
                getAtourPrices(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            List<HtPriceCalendarAtour> tempHtpriceCalendars = htPriceCalendars.stream()
                    .filter(e -> e.getSourceId().equals(htPricePolicy.getSourceId()))
                    .collect(Collectors.toList());
            for (HtPriceCalendarAtour htPriceCalendar : tempHtpriceCalendars) {
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private GetSearchPriceResult getRezenPriceCalendars(String hotelId, String roomTypeCode, Date beginDate,
                                                        Date endDate, List<HtPricePolicy> htPricePolicies) {
        // 价格日历
        List<HtPriceCalendarRezen> htPriceCalendars =
                getRezenPrices(hotelId, roomTypeCode, beginDate, endDate);
        List<GetSearchPriceResult.PriceInfo> priceInfos = new ArrayList<>();
        long id = 1L;
        long inSideId;
        for (HtPricePolicy htPricePolicy : htPricePolicies) {
            GetSearchPriceResult.PriceInfo priceInfo = GetSearchPriceResult.PriceInfo.builder().id(id++)
                    .pricePolicyCode(htPricePolicy.getPricePolicyCode())
                    .pricePolicyName(htPricePolicy.getPricePolicyName()).build();
            boolean flag = false;
            BigDecimal total = BigDecimal.ZERO;
            List<GetSearchPriceResult.PriceDetailInfo> priceDetailInfos = new ArrayList<>();
            inSideId = 1L;
            List<HtPriceCalendarRezen> tempHtpriceCalendars = htPriceCalendars.stream()
                    .filter(e -> e.getBreakfastCount().equals(htPricePolicy.getBreakfastCount())
                            && e.getCancelPolicyType() != null
                            && e.getCancelPolicyType() == 4)
                    .collect(Collectors.toList());
            for (HtPriceCalendarRezen htPriceCalendar : tempHtpriceCalendars) {
                BigDecimal price = htPriceCalendar.getPurchasePrice();
                total = total.add(price);
                GetSearchPriceResult.PriceDetailInfo priceDetailInfo = GetSearchPriceResult.PriceDetailInfo.builder()
                        .id(inSideId++)
                        .breakfastCount(htPriceCalendar.getBreakfastCount())
                        .purchasePrice(price).calDate(htPriceCalendar.getCalDate())
                        .stock(htPriceCalendar.getQuota()).build();
                priceDetailInfos.add(priceDetailInfo);
            }
            if (flag) {
                continue;
            }
            id++;
            priceInfo.setPriceDetailInfos(priceDetailInfos);
            priceInfo.setTotalPrice(total);
            priceInfos.add(priceInfo);
        }
        List<GetSearchPriceResult.DateInfo> dateInfoList = new ArrayList<>();
        AtomicReference<Long> dateId = new AtomicReference<>(1L);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        htPriceCalendars.forEach(htPriceCalendar -> {
            GetSearchPriceResult.DateInfo dateInfo = GetSearchPriceResult.DateInfo.builder().id(dateId.getAndSet(dateId.get() + 1))
                    .calDate(format.format(htPriceCalendar.getCalDate())).build();
            dateInfoList.add(dateInfo);
        });
        return GetSearchPriceResult.builder().dateInfoList(dateInfoList).priceInfoList(priceInfos).build();
    }

    private List<HtPriceCalendarCnbe> getCnbePrices(String hotelId, String roomTypeCode, Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarCnbe> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarCnbe::getHotelId, hotelId);
        if (StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarCnbe::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarCnbe::getCalDate, beginDate, endDate);
        return htPriceCalendarCnbeDao.selectList(queryWrapper);
    }

    private List<HtPriceCalendarAtour> getAtourPrices(String hotelId, String roomTypeCode, Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarAtour> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarAtour::getHotelId, hotelId);
        if (StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarAtour::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarAtour::getCalDate, beginDate, endDate);
        return htPriceCalendarAtourDao.selectList(queryWrapper);
    }

    private List<HtPriceCalendarRezen> getRezenPrices(String hotelId, String roomTypeCode, Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendarRezen> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendarRezen::getHotelId, hotelId);
        if (StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendarRezen::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendarRezen::getCalDate, beginDate, endDate);
        return htPriceCalendarRezenDao.selectList(queryWrapper);
    }

    private void insertOrderLog(String routeId, String orderId, String operator, String info) {
        MgOrderLog mgorderLog = new MgOrderLog();
        mgorderLog.setInfo(String.format("备注%s订单,内容为%s", orderId, info));
        mgorderLog.setOperator(operator);
        mgorderLog.setOrderId(orderId);
        mgorderLog.setRouteId(routeId);
        mgorderLogDao.insert(mgorderLog);
    }

    private List<GetOrderListResult.SourceOrderInfo> getSourceOrderList(List<HtOrderSourceRecord> htOrderSourceRecords,
                                                                        List<HtSourceInfo> htSourceInfos) {
        return htOrderSourceRecords.stream()
                .map(item -> {
                    GetOrderListResult.SourceOrderInfo orderInfo = new GetOrderListResult.SourceOrderInfo();
                    BeanUtil.copyProperties(item, orderInfo);
                    orderInfo.setOrderNotes(item.getResponseBody());

                    orderInfo.setSourceName(htSourceInfos.stream()
                            .filter(e -> e.getSourceId().equals(item.getSourceId())).findFirst()
                            .orElse(new HtSourceInfo()).getSourceName());
                    if (StringUtils.isBlank(item.getRequestBody())) {
                        HtOrderErrorLog htOrderErrorLog = Optional.ofNullable(selectErrorLogs(Lists.newArrayList(item.getBookId())))
                                .orElse(new ArrayList<>()).stream()
                                .findFirst()
                                .orElse(new HtOrderErrorLog());
                        orderInfo.setOrderNotes(StringUtils.isNotBlank(htOrderErrorLog.getResponseBody()) ?
                                htOrderErrorLog.getResponseBody() : orderInfo.getOrderNotes());
                    }
                    return orderInfo;
                }).collect(Collectors.toList());
    }

    private List<String> getExportOrderList(ExportOrderXlsxParam param) {
        LambdaQueryWrapper<HtOrderSourceRecord> sourceRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<HtOrderRouteRecord> routeRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        routeRecordLambdaQueryWrapper.eq(StringUtils.isNotBlank(param.getText()),
                HtOrderRouteRecord::getRouteOrderId, param.getText());
        List<HtOrderRouteRecord> htOrderRouteRecords = new ArrayList<>();
        if (StringUtils.isNotBlank(param.getText())) {
            htOrderRouteRecords = htOrderRouteRecordDao.selectList(routeRecordLambdaQueryWrapper);
        }
        if (CollectionUtils.isNotEmpty(htOrderRouteRecords)) {
            return htOrderRouteRecords.stream()
                    .map(HtOrderRouteRecord::getOrderId).collect(Collectors.toList());
        }

        //根据供应名称查Source表中的OrderId
        sourceRecordLambdaQueryWrapper.eq(StringUtils.isNotBlank(param.getSourceId()),
                HtOrderSourceRecord::getSourceId, param.getSourceId());
        sourceRecordLambdaQueryWrapper.like(StringUtils.isNotBlank(param.getSourceOrderId()),
                HtOrderSourceRecord::getSourceOrderId, param.getSourceOrderId());

        //模糊搜索Source表中的OrderId
        if (StringUtils.isNotBlank(param.getText())) {
            sourceRecordLambdaQueryWrapper.and(e -> e.like(HtOrderSourceRecord::getBookId, param.getText())
                    .or().like(HtOrderSourceRecord::getSourceOrderId, param.getText())
                    .or().like(HtOrderSourceRecord::getOrderId, param.getText())
                    .or().like(HtOrderSourceRecord::getHotelName, param.getText())
                    .or().like(HtOrderSourceRecord::getContactName, param.getText())
                    .or().like(HtOrderSourceRecord::getContactTel, param.getText())
                    .or().like(HtOrderSourceRecord::getGuestName, param.getText()));
        }
        if (null != param.getOrderCreateTime() && param.getArriveDate() != null && param.getDepartDate() != null) {
            sourceRecordLambdaQueryWrapper.between(param.getOrderCreateTime() == 1,
                    HtOrderSourceRecord::getOrderCreateTime,
                    DateUtil.beginOfDay(param.getArriveDate()), DateUtil.endOfDay(param.getDepartDate()));
            sourceRecordLambdaQueryWrapper.between(param.getOrderCreateTime() == 2,
                    HtOrderSourceRecord::getArriveDate,
                    DateUtil.beginOfDay(param.getArriveDate()), DateUtil.endOfDay(param.getDepartDate()));
            sourceRecordLambdaQueryWrapper.between(param.getOrderCreateTime() == 3,
                    HtOrderSourceRecord::getDepartDate,
                    DateUtil.beginOfDay(param.getArriveDate()), DateUtil.endOfDay(param.getDepartDate()));
        }
        sourceRecordLambdaQueryWrapper.select(HtOrderSourceRecord::getOrderId);
        List<String> orderList = htOrderSourceRecordDao.selectList(sourceRecordLambdaQueryWrapper).stream()
                .map(HtOrderSourceRecord::getOrderId).collect(Collectors.toList());
        routeRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 供应有对应单号
        routeRecordLambdaQueryWrapper.in(CollectionUtils.isNotEmpty(orderList),
                HtOrderRouteRecord::getOrderId, orderList);

        routeRecordLambdaQueryWrapper.eq(StringUtils.isNotBlank(param.getRouteId()),
                HtOrderRouteRecord::getRouteId, param.getRouteId());
        routeRecordLambdaQueryWrapper.like(StringUtils.isNotBlank(param.getRouteOrderId()),
                HtOrderRouteRecord::getRouteOrderId, param.getRouteOrderId());
        routeRecordLambdaQueryWrapper.eq(null != param.getRouteOrderStatus(),
                HtOrderRouteRecord::getRouteOrderStatus, param.getRouteOrderStatus());
        routeRecordLambdaQueryWrapper.select(HtOrderRouteRecord::getOrderId);
        return htOrderRouteRecordDao.selectList(routeRecordLambdaQueryWrapper)
                .stream().map(HtOrderRouteRecord::getOrderId).collect(Collectors.toList());
    }

    private List<HtPricePolicy> getPricePolicies(String routeId) {
        LambdaQueryWrapper<HtPricePolicy> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPricePolicy::getRouteId, routeId);
        queryWrapper.eq(HtPricePolicy::getPricePolicyStatus, 1);
        return htPricePolicyDao.selectList(queryWrapper);
    }

    private HtHotelStdInfo getHotelStdInfo(String hotelId, List<String> sourceCodes) {
        LambdaQueryWrapper<HtHotelStdInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtHotelStdInfo::getHotelId, hotelId);
        queryWrapper.in(HtHotelStdInfo::getSourceCode, sourceCodes);
        return htHotelStdInfoDao.selectOne(queryWrapper);
    }

    private List<HtPriceCalendar> getPriceCalenders(String hotelId, String roomTypeCode, Date beginDate, Date endDate) {
        LambdaQueryWrapper<HtPriceCalendar> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HtPriceCalendar::getHotelId, hotelId);
        if (StringUtils.isNotBlank(roomTypeCode)) {
            queryWrapper.eq(HtPriceCalendar::getRoomTypeCode, roomTypeCode);
        }
        queryWrapper.between(HtPriceCalendar::getCalDate, beginDate, endDate);
        return htPriceCalendarDao.selectList(queryWrapper);
    }

    private String getRouteOrderStatus(Integer status) {
        String routeOrderStatus = null;
        if (null != status) {
            switch (status) {
                case 0:
                    routeOrderStatus = "未支付";
                    break;
                case 10:
                    routeOrderStatus = "已支付";
                    break;
                case 20:
                    routeOrderStatus = "已确认";
                    break;
                case 21:
                    routeOrderStatus = "拒绝新订";
                    break;
                case 30:
                    routeOrderStatus = "已完成";
                    break;
                case 40:
                    routeOrderStatus = "申请取消";
                    break;
                case 41:
                    routeOrderStatus = "同意取消";
                    break;
                case 42:
                    routeOrderStatus = "拒绝取消";
                    break;
                case 50:
                    routeOrderStatus = "已退款";
                    break;
                default:
                    break;
            }
        }
        return routeOrderStatus;
    }

    private String getSourceOrderStatus(Integer status) {
        String sourceOrderStatus = null;
        if (null != status) {
            switch (status) {
                case 0:
                    sourceOrderStatus = "待确认";
                    break;
                case 1:
                    sourceOrderStatus = "预定成功";
                    break;
                case 2:
                    sourceOrderStatus = "已取消";
                    break;
                case 3:
                    sourceOrderStatus = "预定未到";
                    break;
                case 4:
                    sourceOrderStatus = "已入住";
                    break;
                case 5:
                    sourceOrderStatus = "已离店";
                    break;
                case 6:
                    sourceOrderStatus = "预定失败";
                    break;
                default:
                    break;
            }
        }
        return sourceOrderStatus;
    }

    private MgUserInfo getUser(HttpServletRequest req) {
        String token = req.getHeader("token");
        if (org.apache.commons.lang.StringUtils.isBlank(token)) {
            throw new RuntimeException("请先登录!");
        }
        String id = JwtUtil.parseJwt(token).getId();
        return Optional.ofNullable(mgUserInfoDao.selectById(id)).orElse(new MgUserInfo());
    }
}
